package com.boarsoft.auth;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.boarsoft.common.Authorized;
import com.boarsoft.common.Unauthorize;
import com.boarsoft.common.Util;
import com.boarsoft.webapp.util.ServletUtil;

/**
 * 面向业务方法的权限AOP切面
 * 
 * @author Mac_J
 *
 */
public class SpringWebAuthAdvice {
	private static Logger log = LoggerFactory.getLogger(SpringWebAuthAdvice.class);

	protected PowerCheck powerCheck;

	protected AuthReplyer replyer = new DefaultAuthReplyer();

	protected String key = "token";

	// @Around(value = "target(com.boarsoft.boar.demo.MyService)")
	// @Around("@annotation(org.springframework.web.bind.annotation.RequestMapping)&&@annotation(com.boarsoft.common.Authorized)")
	// @Around("@annotation(com.boarsoft.common.Authorized)")
	public Object authorize(ProceedingJoinPoint jp) throws Throwable {
		ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest rq = sra.getRequest();
		// 获取id（可能是userId也可能是token）
		String id = rq.getParameter(key);
		if (Util.strIsEmpty(id)) {
			id = ServletUtil.getCookie(rq, key);
			if (Util.strIsEmpty(id)) {
				id = rq.getHeader(key);
			}
		}
		// 有token则检查用户权限
		if (Util.strIsEmpty(id)) {
			log.debug("Invalid user {}/{} access", key, id);
			return replyer.reply(403);
		}

		// 获取方法上的注解
		MethodSignature signature = (MethodSignature) jp.getSignature();
		Method method = signature.getMethod();// jp.getArgs()[0];
		// 默认用URI作为模块名
		String module = rq.getRequestURI();
		// 被拦截的方法如果有Unauthorize注册则直接放行
		if (method.isAnnotationPresent(Unauthorize.class)) {
			Unauthorize a = method.getAnnotation(Unauthorize.class);
			if (Util.strIsNotEmpty(a.code())) {
				module = a.code();
			}
			log.debug("Skip authorize user {} access {}", id, module);
			return jp.proceed();
		}
		// 如果有Authorized注解，从注解获取模块编号
		if (method.isAnnotationPresent(Authorized.class)) {
			Authorized a = method.getAnnotation(Authorized.class);
			module = a.code();
		}
		log.debug("Authorize user {} access {}", id, module);
		// 检查用户权限
		if (powerCheck.check(id, module)) {
			// rq.setAttribute(userIdKey, rq.getHeader(userIdKey));
			return jp.proceed();
		}
		return replyer.reply(401);
	}

	protected ResponseEntity<Object> getJsonResponse(Object ro) {
		HttpHeaders hh = new HttpHeaders();
		hh.setContentType(MediaType.APPLICATION_JSON);
		hh.set("charset", "UTF-8");
		return new ResponseEntity<Object>(ro, hh, HttpStatus.OK);
	}

	public String getKey() {
		return key;
	}

	public void setKey(String key) {
		this.key = key;
	}

	public AuthReplyer getReplyer() {
		return replyer;
	}

	public void setReplyer(AuthReplyer replyer) {
		this.replyer = replyer;
	}

	public PowerCheck getPowerCheck() {
		return powerCheck;
	}

	public void setPowerCheck(PowerCheck powerCheck) {
		this.powerCheck = powerCheck;
	}

}
